/*
 * io.c
 *
 *  Created on: 2016-10-17
 *      Author: jared
 */
#include "types.h"
#include "constants.h"
#include "defs.h"
#include "mm.h"
#include "x86.h"

#define CRTPORT 0x3d4
static ushort *crt = (ushort*) P2V(0xb8000);  // CGA memory
static int panicked = 0;

uint conlock;

void consoleinit(void) {
	conlock = 0;
	ioapicenable(IRQ_KBD, 0);
}

void printint(int xx, int base, int sign) {
	static char digits[] = "0123456789abcdef";
	char buf[16];
	int i;
	uint x;

	if (sign && (sign = xx < 0))
		x = -xx;
	else
		x = xx;

	i = 0;
	do {
		buf[i++] = digits[x % base];
	} while ((x /= base) != 0);

	if (sign)
		buf[i++] = '-';

	while (--i >= 0)
		consputc(buf[i]);
}

void consputc(int c) {
	if (panicked) {
		cli();
		for (;;)
			;
	}
	cgaputc(c);
}

void cgaputc(int c) {
	int pos;

	// Cursor position: col + 80*row.
	outb(CRTPORT, 14);
	pos = inb(CRTPORT + 1) << 8;
	outb(CRTPORT, 15);
	pos |= inb(CRTPORT + 1);

	if (c == '\n')
		pos += 80 - pos % 80;
	else {
//	  *((ushort*)(0xb8000+pos*2)) = (c&0xff) | 0x0700;
//	  pos+=1;
		crt[pos++] = (c & 0xff) | 0x0700;  // 黑底白字
	}

	if ((pos / 80) >= 24) {  // Scroll up.
		memmove(crt, crt + 80, sizeof(crt[0]) * 23 * 80);
		pos -= 80;
		memset(crt + pos, 0, sizeof(crt[0]) * (24 * 80 - pos));
	}

	setCursor(pos);
	crt[pos] = ' ' | 0x0700;
}

void setCursor(int pos) {
	//高位放14号寄存器
	outb(CRTPORT, 14);
	outb(CRTPORT + 1, pos >> 8);
	//低位放15号寄存器
	outb(CRTPORT, 15);
	outb(CRTPORT + 1, pos);
}

void clearScreen() {
	//光标移动到最开始
	setCursor(0);
	int i;
	for (i = 0; i < 2000; i++) {
		cgaputc(' ');
	}
	//光标恢复到最开始
	setCursor(0);
}

void showWelcome() {
	char * welcome = "HELLO, WELCOME! -- BY MYJOS.\n";
	int i, len = strlen(welcome);
	for (i = 0; i < len; i++) {
		cgaputc(welcome[i]);
	}
}

void easyprint(char * s) {
	int i, len = strlen(s);
	for (i = 0; i < len; i++) {
		cgaputc(s[i]);
	}
}

void printk(char *fmt, ...) {
	int i, c;
	uint *argp;
	char *s;

	acquire(&conlock);

	if (fmt == 0)
		panic("null fmt");

	argp = (uint*) (void*) (&fmt + 1);
	for (i = 0; (c = fmt[i] & 0xff) != 0; i++) {
		if (c != '%') {
			consputc(c);
			continue;
		}
		c = fmt[++i] & 0xff;
		if (c == 0)
			break;
		switch (c) {
		case 'd':
			printint(*argp++, 10, 1);
			break;
		case 'x':
		case 'p':
			printint(*argp++, 16, 0);
			break;
		case 's':
			if ((s = (char*) *argp++) == 0)
				s = "(null)";
			for (; *s; s++)
				consputc(*s);
			break;
		case '%':
			consputc('%');
			break;
		default:
			// Print unknown % sequence to draw attention.
			consputc('%');
			consputc(c);
			break;
		}
	}

	release(&conlock);
}

void panic() {
	char * panic = "PANIC!\n";
	int i, len = strlen(panic);
	for (i = 0; i < len; i++) {
		cgaputc(panic[i]);
	}
	for (;;)
		;
}

void panicInfo(char *s) {
	int i, len = strlen(s);
	for (i = 0; i < len; i++) {
		cgaputc(s[i]);
	}
	for (;;)
		;
}

void consoleintr(int (*getc)(void)) {
	int c;

	while ((c = getc()) >= 0) {
		switch (c) {
		case 'p':  // Process listing.
			procdump();
			break;
		default:
			break;
		}
	}
}

uchar normalmap[256] =
{
  NO,   0x1B, '1',  '2',  '3',  '4',  '5',  '6',  // 0x00
  '7',  '8',  '9',  '0',  '-',  '=',  '\b', '\t',
  'q',  'w',  'e',  'r',  't',  'y',  'u',  'i',  // 0x10
  'o',  'p',  '[',  ']',  '\n', NO,   'a',  's',
  'd',  'f',  'g',  'h',  'j',  'k',  'l',  ';',  // 0x20
  '\'', '`',  NO,   '\\', 'z',  'x',  'c',  'v',
  'b',  'n',  'm',  ',',  '.',  '/',  NO,   '*',  // 0x30
  NO,   ' ',  NO,   NO,   NO,   NO,   NO,   NO,
  NO,   NO,   NO,   NO,   NO,   NO,   NO,   '7',  // 0x40
  '8',  '9',  '-',  '4',  '5',  '6',  '+',  '1',
  '2',  '3',  '0',  '.',  NO,   NO,   NO,   NO,   // 0x50
  [0x9C] '\n',      // KP_Enter
  [0xB5] '/',       // KP_Div
  [0xC8] KEY_UP,    [0xD0] KEY_DN,
  [0xC9] KEY_PGUP,  [0xD1] KEY_PGDN,
  [0xCB] KEY_LF,    [0xCD] KEY_RT,
  [0x97] KEY_HOME,  [0xCF] KEY_END,
  [0xD2] KEY_INS,   [0xD3] KEY_DEL
};

int kbdgetc(void) {
	uint st, data, c;
	st = inb(KBSTATP);
	if ((st & KBS_DIB) == 0)
		return -1;
	data = inb(KBDATAP);

	c = normalmap[data];
	return c;
}

void kbdintr(void) {
	consoleintr(kbdgetc);
}
